#include <iostream>
#include <string>
#include <vector>
#include <sstream>
#include <unordered_map>
#include <fstream>
// stirngstream
#include "Common.hpp"
const std::string sep = "\r\n";
const std::string Linesep = " ";                // 行分隔符
const std::string HeaderLinesep = ": ";         // 行分隔符
const std::string BlankLine = sep;              // 加入空行
const std::string defaultHomepage = "wwwroot";  // 根目录路径
const std::string http_vesion = "HTTP/1.0";     // 服务器版本
const std::string page404 = "wwwroot/404.html"; // 服务器版本
const std::string firstpage = "index.html";     // 首页文件名

// 这代码是视了对完整性的检查的代码。
// 这种模式称为B/S模式
class HttpRequest
{
private:
    std::string _req_line;
    // 请求行解析出来的字段
    std::string _method;
    std::string _uri; // 用户只想要这个，这个是用户请求的资源路径
    std::string _path;
    std::string _args;
    std::string _version;

    std::vector<std::string> _req_header;
    std::string _blank_line;
    std::string _req_body; // 可能带参数
    std::unordered_map<std::string, std::string> _header_kv;

    bool _isexec = false; //

    // 反序列化要解析出我们的字段。
    // 隐藏起来，没必要放出去
    void ParseReqLine(std::string &request_str, const std::string &sep)
    {
        (void)sep;
        std::stringstream ss(_req_line);
        ss >> _method >> _uri >> _version;
        // _uri = defaultHomepage + _uri;
    }

public:
    HttpRequest() {}
    ~HttpRequest() {}
    bool IsHasArgs() { return _isexec; }
    // 得到对应的文件内容
    // vesion-1——因为是getline方式读取的所以不能读取二进制内容(二进制中可能有\0getline遇到这就截断了)
    // std::string GetContent()
    // {
    //     std::string content;
    //     std::ifstream file(_uri);
    //     if (!file.is_open())
    //         return std::string();
    //     std::string line;
    //     while (std::getline(file, line))
    //     {
    //         content += line;
    //     }
    //     file.close();
    //     return content;
    // }
    // vesion-2——使用ifstream读取文件，可以读取二进制内容
    std::string GetContent(const std::string path)
    {
        std::string content;
        std::ifstream file(path, std::ios::binary);
        if (!file.is_open())
            return std::string();
        file.seekg(0, std::ios::end);
        int filesize = file.tellg();
        file.seekg(0, std::ios::beg);
        content.resize(filesize);
        file.read((char *)content.c_str(), filesize);
        file.close(); // 函数结束会自动析构，这里显示析构代码逻辑更清晰
        return content;
    }
    const std::string Uri() const
    {
        return _uri;
    }
    void SetUri(const std::string newuri)
    {
        _uri = newuri;
    }
    std::string Path() { return _path; }
    std::string Args() { return _args; }
    std::string Suffix() // Suffix()函数用于获取文件后缀名
    {
        // _uri ->wwwroot/index.html
        // 找到最后一个/的位置
        auto pos = _uri.rfind('.');
        if (pos == std::string::npos)
            return std::string(".html"); // 硬编码
        else
            return _uri.substr(pos);
    }
    bool ParseHeaderKV()
    {
        std::string key, value;
        for (auto &head : _req_header)
        {
            if (SplitString(head, HeaderLinesep, &key, &value))
            {
                _header_kv.insert(std::make_pair(key, value));
            }
        }
        return true;
    }

    bool ParseHeaderLine(std::string &request_str)
    {
        std::string line;
        while (true)
        {
            bool r = ParseOneLine(request_str, &line, sep);
            if (r && !line.empty())
            {
                _req_header.push_back(line);
            }
            else if (r && line.empty())
            {
                // 读到空行
                _blank_line = sep;
                break;
            }
            else
            {
                return false; // 读到末尾 || 解析失败
            }
        }
        ParseHeaderKV();
        return true;
    }

    void Deserialize(std::string &request_str) // 反序列化
    {
        // // 实际上是字符串处理
        std::cout << "############" << std::endl;
        std::cout << "解析之前" << request_str << std::endl;
        if (ParseOneLine(request_str, &_req_line, sep)) // 1.第一行解析
        {
            // 上面解析了一行，进一步解析第一行请求行中的详细字段
            ParseReqLine(request_str, Linesep);
            // 2.请求报头的解析
            ParseHeaderLine(request_str);
            // 3.请求正文的解析
            // 正文就是剩下的内容了
            _req_body = request_str;
            // 请求中可能包含参数比如POST方法时，
            if (_method == "POST") // POST方法参数在请求报头中
            {
                // 这里就不判断是否有错了，判断是一定有内容的
                _isexec = true;
                _args = _req_body;
                _path = _uri;
                std::cout << "POST: _path: " << _path << std::endl;
                std::cout << "POST: _args: " << _args << std::endl;
            }
            else if (_method == "GET") // GET方法参数在URL中
            {
                auto pos = _uri.rfind("?");
                if (pos != std::string::npos)
                {
                    _isexec = true;
                    // /login?name=lisi&passwd=123456
                    // 解析出参数
                    _path = _uri.substr(0, pos);  // 左半部分去进行功能路由
                    _args = _uri.substr(pos + 1); // 右半部分就是参数
                    std::cout << "POST: _path: " << _path << std::endl;
                    std::cout << "POST: _args: " << _args << std::endl;
                }
            }
        }
    }
    void Print()
    {
        std::cout << "—————————————请求行—————————————————" << std::endl;
        std::cout << "_method :" << _method << std::endl;
        std::cout << "_url :" << _uri << std::endl;
        std::cout << "_version :" << _version << std::endl;
        std::cout << "—————————————请求报头————————————————" << std::endl;
        for (auto &line : _req_header)
        {
            std::cout << line << std::endl
                      << std::endl;
        }
        std::cout << "kv后的" << std::endl;
        for (auto &kv : _header_kv)
        {
            std::cout << kv.first << "#";
            std::cout << kv.second << std::endl
                      << std::endl;
        }
        std::cout << _blank_line << std::endl;
        std::cout << "—————————————请求正文————————————————" << std::endl;
        std::cout << _req_body << std::endl;
        std::cout << "————————————————————————————————" << std::endl;
    }
};

// 对于http，任何请求，都要有应答
class HttpResponse
{
private:
    std::string Code2Desc(int code)
    {
        switch (code)
        {
        case 200:
            return "OK";
        case 301:
            return "Moved Permanently";
        case 302:
            return "Found";
        case 404:
            return "Not Found";
        default:
            return "Unknown";
        }
    }

private:
    // 必备的要素
    std::string _vesion;                                     // 版本号
    int _status_code;                                        // 转态码
    std::string _status_desc;                                // 状态码描述
    std::string _content;                                    // 给用户返回的内容
    std::unordered_map<std::string, std::string> _header_kv; // 应答

    // 响应行，构建应答
    std::string _resp_line;
    std::vector<std::string> _resp_header;
    std::string _blank_line;
    std::string _resp_body; //

private:
    std::string Suffix2Desc(const std::string &suffix)
    {
        if (suffix == ".html")
            return "text/html";
        else if (suffix == ".jpg")
            return "image/jpeg";
        else
            return "application/octet-stream";
    }

public:
    HttpResponse()
        : _vesion(http_vesion), _blank_line(sep)
    {
    }
    ~HttpResponse() {}
    void SetHeader(const std::string &k, const std::string &v)
    {
        _header_kv[k] = v;
    }

    void Serialize(std::string *resp_str)
    {
        // 第一行，请求行
        for (auto &header : _header_kv)
        {
            _resp_header.push_back(header.first + HeaderLinesep + header.second + sep);
        }
        _resp_line = _vesion + Linesep + std::to_string(_status_code) + Linesep + _status_desc + sep;

        // 序列化
        *resp_str = _resp_line;
        // 请求报头
        for (auto &line : _resp_header)
        {
            *resp_str += (line + sep);
        }

        // 空行
        *resp_str += _blank_line;

        // 请求正文的解析

        *resp_str += _resp_body;
    }

    void SetBody(const std::string &body)
    {
        _resp_body = body;
    }
    void SetCode(int code)
    {
        _status_code = code;
        _status_desc = Code2Desc(_status_code);
    }
    // vesion-2-重定向功能void Build(HttpRequest &req)
    void Build(HttpRequest &req)
    {
        // #ifdef这种用法是将代码分块，下面做法就是我只要#ifdef和#else之间的代码
        // #define TestRedir 1
        // #ifdef TestRedir
        //         // 重定向功能演示
        //         _status_code = 302;
        //         _status_desc = Code2Desc(_status_code);
        //         SetHeader("Location", "https://www.bilibili.com/"); // 直接重定向
        //         for (auto &header : _header_kv)
        //         {
        //             _resp_header.push_back(header.first + HeaderLinesep + header.second + sep);
        //         }
        // #else
        std::string uri = defaultHomepage + req.Uri();
        // back是字符串的最后一段字符
        // 每一个字目录最好都加上index.html
        if (uri.back() == '/') // 如果uri以/结尾，则加上默认的首页文件名默认就是访问首页
        {
            // 默认加上一个首页信息
            uri += firstpage;
            req.SetUri(uri);
        }
        // 获得内容
        std::cout<<"————客户端在请求——————"<<std::endl;
        _content = req.GetContent(uri);
        if (_content.empty())
        {
            // 这里代表用户请求的资源不存在
            // 虽然是404但是也要返回一个404的响应报文，404对应的页面
            _status_code = 404;
            // 不能单纯的返回一个404还要返回一个404页面
            req.SetUri(page404);
            _content = req.GetContent(req.Uri()); // 这里是重定向到404页面
            // _status_desc = "Not Found";//这是对转态码的硬编码，应该要HTTP自主决定
        }
        else
        {
            _status_code = 200;
            // _status_desc = "OK";
        }
            _status_desc = Code2Desc(_status_code);

        if (!_content.empty())
        {
            SetHeader("Content-Length", std::to_string(_content.size()));
        }
        std::string Mime_Type = Suffix2Desc(req.Suffix());
        SetHeader("Content-Type", Mime_Type);
        _resp_body = _content;
    }

    // vesion-1
    //  void Build(HttpRequest &req)
    //  {
    //      std::string uri = req.Uri();
    //      // back是字符串的最后一段字符
    //      // 每一个字目录最好都加上index.html
    //      if (uri.back() == '/') // 如果uri以/结尾，则加上默认的首页文件名默认就是访问首页
    //      {
    //          // 默认加上一个首页信息
    //          uri += firstpage;
    //          req.SetUri(uri);
    //      }
    //      // 获得内容
    //      _content = req.GetContent();
    //      if (_content.empty())
    //      {
    //          // 这里代表用户请求的资源不存在
    //          // 虽然是404但是也要返回一个404的响应报文，404对应的页面
    //          _status_code = 404;
    //          _status_desc = Code2Desc(_status_code);
    //          // 不能单纯的返回一个404还要返回一个404页面
    //          req.SetUri(page404);
    //          _content = req.GetContent();
    //          // _status_desc = "Not Found";//这是对转态码的硬编码，应该要HTTP自主决定
    //      }
    //      else
    //      {
    //          _status_code = 200;
    //          _status_desc = Code2Desc(_status_code);
    //          // _status_desc = "OK";
    //      }
    //      if (!_content.empty())
    //      {
    //          SetHeader("Content-Length", std::to_string(_content.size()));
    //      }
    //      std::string Mime_Type = Suffix2Desc(req.Suffix());
    //      SetHeader("Content-Type", Mime_Type);
    //      for (auto &header : _header_kv)
    //      {
    //          _resp_header.push_back(header.first + HeaderLinesep + header.second + sep);
    //      }
    //  }
};
